#pragma once

#include "mono/pch.h"
#include "mono/Method.h"
#include "mono/Object.h"
#include "mono/Field.h"

namespace mono
{
    struct Clazz
    {
     
        struct Desc
        {
            std::string m_Namespace;

            std::string m_Name;

            MonoImage *image;

            bool operator<(const Clazz::Desc &other) const
            {
                return std::tie(m_Namespace, m_Name) < std::tie(other.m_Namespace, other.m_Name);
            };

        } m_Desc;

        MonoClass *klass;

        bool m_IsEnum;

        bool m_Available;

        std::vector<std::shared_ptr<mono::Field>> m_Fields, m_EnumValues;

        std::map<mono::Method::Desc, std::shared_ptr<mono::Method>> m_Methods;

        Clazz(const Desc &desc)
            : m_Desc(desc), m_IsEnum(false)
        {
            m_Available = Init();
        }

        std::shared_ptr<Object> NewObject()
        {
            auto obj = mono_object_new(mono_domain_get(), klass);
            return std::make_shared<mono::Object>(obj, klass);
        };

        bool Init();

        bool LoadMethod(const std::string &name, int numParam)
        {
            Method::Desc desc;
            desc.m_Name = name;
            desc.m_NumParam = numParam;
            desc.clazz = klass;

            return LoadMethod(desc);
        };
        
        std::shared_ptr<Method> GetMethod(const std::string &name, int numParam);

    private:
        bool LoadMethod(const Method::Desc &desc);
    };
};